<template>
  <el-card>
    <div class="card-header">
      <span>菜单管理</span>
    </div>
  </el-card>
  <el-card class="content">
      <el-form-item>
        <perms-button
            perms="privilege:menu:list"
            :type="Types.primary"
            :plain="true"
            @action="list"/>
      </el-form-item>
    <el-table
        v-if="tableVisible"
        :data="menuList"
        :border="true"
        row-key="id"
        :default-expand-all="expand"
        :tree-props="{ children: 'children', hasChildren: '!!children' }"
        class="table"
    >
      <template #empty>
        <el-empty/>
      </template>
      <el-table-column label="">
        <template #header>
          <perms-button
              perms="privilege:menu:add"
              :type="Types.primary"
              :size="Sizes.default"
              :plain="true"
              @action="addMenu"/>
          <el-button @click="switchExpand(true)" size="default">展开全部</el-button>
          <el-button @click="switchExpand(false)" size="default">折叠全部</el-button>
        </template>
        <el-table-column prop="name" label="菜单名称" min-width="200">
          <template #default="scope">
            <el-link :icon="scope.row.icon">{{ scope.row.name }}</el-link>
          </template>
        </el-table-column>
        <el-table-column prop="path" label="菜单路径" min-width="160"/>
        <el-table-column prop="component" label="组件路径" min-width="160"/>
        <el-table-column prop="perms" label="权限标识" min-width="160"/>
        <el-table-column prop="sort_id" label="排序" width="60" align="center"/>
        <el-table-column prop="type" label="类型" width="90" align="center">
          <template #default="scope">
            <el-tag size="small" :type="typeType(scope.row.type)">{{ typeText(scope.row.type) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="hidden" label="显示状态" width="90" align="center">
          <template #default="scope">
            {{ scope.row.hidden ? '隐藏' : '显示' }}
          </template>
        </el-table-column>
        <el-table-column label="操作" min-width="120">
          <template #default="scope">
            <perms-link
                perms="privilege:menu:add"
                :type="Types.primary"
                :plain="true"
                @action="addSubMenu(scope.row)"/>
            <perms-link
                perms="privilege:menu:update"
                :type="Types.warning"
                :plain="true"
                @action="editMenu(scope.row)"/>
            <el-popconfirm
                :title="`确定删除菜单[${scope.row.name}]吗?`"
                :icon="InfoFilled"
                icon-color="#F56C6C"
                cancel-button-text="取消"
                confirm-button-text="确认删除"
                cancel-button-type="info"
                confirm-button-type="danger"
                @confirm="deleteMenu(scope.row.id)"
                width="300"
            >
              <template #reference>
                <perms-link
                    perms="privilege:menu:delete"
                    :type="Types.danger"
                    :plain="true"/>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>

      </el-table-column>
    </el-table>
  </el-card>
  <el-dialog
      v-model="visible"
      :title="title"
      draggable
      width="800"
      :close-on-click-modal="false"
      @close="handleClose"
  >
    <el-form ref="formRef" :model="menuForm" :rules="rules" label-width="100">
      <el-row>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="上级菜单" prop="parent_id">
            <el-cascader
                :options="options"
                :props="props"
                v-model="cascaderParent"
                ref="parentRef"
                clearable
                @change="handleParentChange"
                style="width: 360px">
              <template #default="{ node, data }">
                <span>{{ data.name }}</span>
                <span v-if="!node.isLeaf"> ({{ !!data.children ? data.children.length : 0 }}) </span>
              </template>
            </el-cascader>
          </el-form-item>
          <el-form-item label="菜单名称" prop="name">
            <el-input v-model="menuForm.name" style="width: 360px" placeholder="例如：权限管理"/>
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="菜单类型" prop="type">
            <el-radio-group v-model.number="menuForm.type" :disabled="action==='editMenu'">
              <el-radio :label="1">菜单</el-radio>
              <el-radio :label="2">按钮</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="菜单排序" prop="sort_id">
            <el-input v-model.number="menuForm.sort_id" style="width: 360px"/>
          </el-form-item>
        </el-col>
      </el-row>
      <el-divider/>
      <el-row>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="菜单图标" prop="icon">
            <el-popover
                ref="popover"
                placement="right"
                width="880"
                popper-class="icon-popper"
                trigger="click"
            >
              <template #reference>
                <el-button :icon="menuForm.icon"/>
              </template>
              <div class="icon-content">
                  <el-row>
                      <el-col :span="4" v-for="(name,idx) in iconList" :key="idx" :icon="name" style="text-align: center">
                          <div @click="selectIcon(name)" style="border:1px solid #cccccc;padding: 10px">
<!--                              <el-button :key="idx" :icon="name" size="large" style="margin-bottom: 5px"></el-button>-->
                            <component :is="name" style="width: 24px"></component>
                            <div style="font-size: 12px">{{name}}</div>
                          </div>
                      </el-col>
                  </el-row>
              </div>
            </el-popover>
          </el-form-item>
          <el-form-item label="菜单路径" prop="path">
            <el-input v-model="menuForm.path" :disabled="menuForm.type!==1" style="width: 360px"/>
          </el-form-item>
          <el-form-item label="组件路径" prop="component">
            <el-input v-model="menuForm.component" :disabled="menuForm.type!==1" style="width: 360px"/>
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
          <el-form-item label="权限标识" prop="perms">
            <el-input v-model="menuForm.perms" :disabled="menuForm.type===1" style="width: 360px"/>
          </el-form-item>
          <el-form-item label="是否固定" prop="fixed">
            <el-radio-group v-model="menuForm.fixed" :disabled="menuForm.type!==1">
              <el-radio :label="false">不固定</el-radio>
              <el-radio :label="true">固定</el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="是否隐藏" prop="hidden">
            <el-radio-group v-model="menuForm.hidden">
              <el-radio :label="false">显示</el-radio>
              <el-radio :label="true">隐藏</el-radio>
            </el-radio-group>
          </el-form-item>
        </el-col>
      </el-row>
      <el-form-item label="备注">
        <el-input type="textarea" rows="5" placeholder="请输入备注"></el-input>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" plain @click="handleSubmit">提交</el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
//菜单列表表单
import {nextTick, onMounted, reactive, ref} from "vue";
import {ListRequest, Menu} from "@/interface/menu";
import {MenuAddR, MenuListR, MenuRemoveR, MenuUpdateR} from "@/api/menu";
import {CascaderInstance, ElMessage, FormInstance, FormRules} from "element-plus";
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import Node from "element-plus/es/components/cascader-panel/src/node";
import {InfoFilled} from "@element-plus/icons-vue";
import {LoadMenuTree} from "@/utils/menu";
import {Sizes, Types} from "@/interface/enum";
import PermsButton from '@/components/PermsButton.vue'
import PermsLink from '@/components/PermsLink.vue'
import {DeleteRequest} from "@/interface/user";

const initMenuForm = () => {
  return <Menu>{
    id: 0,
    type: 1,
    sort_id: 0,
    parent_id: 0,
    path: '',
    component: '',
    name: '',
    transition: '',
    icon: 'search',
    hidden: false,
    fixed: true,
    perms: '',
    remark: '',
  }
}

//级联选择器
const options = ref<Menu[]>()
const props = ref({label: 'name', value: 'id', checkStrictly: true})

const menuForm = ref<Menu>(initMenuForm())
const iconList = ref<Array<string>>([])
const icon = ref<string>('search')
//表单校验
const formRef = ref<FormInstance>()
const parentRef = ref<CascaderInstance>()

//表格展开属性
const expand = ref<boolean>(false)
const tableVisible = ref<boolean>(true)

const menuList = ref<Menu[]>()
//dialog可见
const visible = ref<boolean>(false)
const title = ref<string>('')
const action = ref<string>('') //表单动作：addMenu，新增菜单； addSubMenu，新增子菜单； editMenu，修改菜单

const rules = reactive<FormRules>({
  parent_id: [
    {required: true, message: '必填', type: "number", trigger: ['blur', 'change']}
  ],
  type: [
    {required: true, message: '请选择指定的菜单类型', type: "enum", enum: [1, 2, 3], trigger: ['blur', 'change']},
  ],
  name: [
    {required: true, message: '必填', type: "string", trigger: ['blur', 'change']}
  ],
  icon: [
    {required: true, message: '必选', type: "string", trigger: ['blur', 'change']}
  ],
  path: [
    // {required: true, message: '必填', type: "string", trigger: ['blur', 'change']}
  ],
  component: [
    // {required: true, message: '必填', type: "string", trigger: ['blur', 'change']}
  ],
  sort_id: [
    {required: true, message: '必填', type: "number", trigger: ['blur', 'change']}
  ],
  fixed: [
    {required: true, message: '必填', type: "boolean", trigger: ['blur', 'change']}
  ],
  hidden: [
    {required: true, message: '必填', type: "boolean", trigger: ['blur', 'change']}
  ],
})

const list = () => {
  MenuListR().then(res => res.data).then(res => {
    switch (res.code) {
      case 200:
        //菜单列表=>菜单树
        let menus = res.data as Menu[]
        let parents = menus.filter((m) => m.parent_id === 0)
        let children = menus.filter((m) => m.parent_id !== 0)

        LoadMenuTree(parents, children)

        menuList.value = parents

        let menu: Menu = initMenuForm()
        menu.name = '主类目'
        menu.children = parents
        options.value = [menu]

        parentIds.value = new Map<number, Array<number>>()
        loadParentIds([menu])
        break
      default:
        //ElMessage.error(res.msg)
    }
  })
}

//菜单展开
const switchExpand = (val:boolean) =>{
  tableVisible.value=false
  expand.value = val

  nextTick(()=>{
    tableVisible.value=true
  })
}

const typeText = (val: number) => {
  switch (val) {
    case 1:
      return '菜单'
    case 2:
      return '按钮'
    default:
      console.log('未知菜单类型：', val)
      return '未知'
  }
}

const typeType = (val: number) => {
  switch (val) {
    case 1:
      return 'success'
    case 2:
      return 'warning'
    case 3:
      return 'danger'
    default:
      return 'info'
  }
}

//选择图标
const selectIcon = (name: string) => {
  icon.value = name
  menuForm.value.icon = name
}

//获取菜单节点的完整级联路径
const parentIds = ref<Map<number, Array<number>>>(new Map<number, Array<number>>())
const cascaderParent = ref<Array<number>>([])
const loadParentIds = (menus: Menu[]) => {
  parentIds.value.set(0, [])
  menus.forEach((menu) => {
    //查询父级菜单的路径
    let parentId: Array<number> = []
    if (!parentIds.value.has(menu.parent_id)) {
      parentIds.value.set(menu.parent_id, [])
    }

    parentId = parentIds.value.get(menu.parent_id) as Array<number>
    parentIds.value.set(menu.id, [...parentId, menu.parent_id])

    if (!!menu.children && menu.children.length > 0) {
      loadParentIds(menu.children)
    }
  })
}

const handleParentChange = (value: Array<number>) => {
  console.log('父菜单变动：', value)
}

//添加菜单
const addMenu = () => {
  visible.value = true
  title.value = '新增菜单'
  action.value = 'addMenu'
  menuForm.value = initMenuForm()
}


//添加子菜单
const addSubMenu = (parent: Menu) => {
  title.value = '新增菜单'
  action.value = 'addSubMenu'
  visible.value = true
  menuForm.value = initMenuForm()
  menuForm.value.parent_id = parent.id
  cascaderParent.value = [...parentIds.value.get(parent.id) as Array<number>, parent.id]
}

//修改菜单
const editMenu = (menu: Menu) => {
  title.value = '修改菜单'
  action.value = 'editMenu'
  visible.value = true
  menuForm.value = JSON.parse(JSON.stringify(menu))
  cascaderParent.value = parentIds.value.get(menu.id) as Array<number>
}

//提交表单
const handleSubmit = () => {
  //设置parent_id
  let nodes = parentRef.value?.getCheckedNodes(false) //是否只监测leaf节点
  // console.log('菜单节点树：', JSON.stringify(nodes))
  if (!!nodes && nodes.length > 0) {
    menuForm.value.parent_id = (nodes.pop() as Node).value as number
  } else {
    menuForm.value.parent_id = 0
  }

  //表单校验
  formRef.value?.validate((isValid) => {
    if (!isValid) {
      return
    }

    switch (action.value) {
      case 'addMenu':
        MenuAddR(menuForm.value).then(res => res.data).then((res) => {
          switch (res.code) {
            case 200:
              handleClose()
              list()
              break
            default:
          }
        })
        break
      case 'addSubMenu':
        MenuAddR(menuForm.value).then(res => res.data).then(res => {
          switch (res.code) {
            case 200:
              handleClose()
              list()
              break
            default:
          }
        })
        break
      case 'editMenu':
        MenuUpdateR(menuForm.value).then(res => res.data).then(res => {
          switch (res.code) {
            case 200:
              ElMessage.success(res.msg)
              handleClose()
              list()
              break
            default:
          }
        }).catch(err => {
          ElMessage.error(err.toString())
        })
        break
      default:
        ElMessage.warning('未知操作')
    }
  })
}

//删除菜单
const deleteMenu = (id: number) => {
  console.log('删除菜单：', id)
  let req = <DeleteRequest>{id: id}
  MenuRemoveR(req).then(res => res.data).then(res => {
    switch (res.code) {
      case 200:
        ElMessage.success(res.msg)
        list()
        break
      default:
    }
  })
}

//关闭表单
const handleClose = () => {
  visible.value = false
  // formRef.value?.resetFields()
  menuForm.value = initMenuForm()
}

//图标列表
const loadIcons = () => {
  iconList.value = []
    console.log('菜单图标数量：', Object.entries(ElementPlusIconsVue).length)
  for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    // app.component(key, component)
      console.log('icon:', key)
    // iconList.value.push((component.__file as string).slice(0, -4)) //删除文件后缀[.vue]
    iconList.value.push(key)
  }
    console.log('菜单图标数量：', iconList.value.length)
}

onMounted(() => {
  list()

  loadIcons()

})

</script>

<style scoped lang="less">
.el-card {
  margin-bottom: 10px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.table{
  height: calc(100vh - 315px)
}

.page {
  margin-top: 10px;
}

.links {
  padding-right: 10px;
}

//图标气泡卡片
.icon-popper {
  max-height: 500px;
}

.icon-content {
  max-height: 650px;
  width: 100%;
  overflow: auto;
  overflow-x: hidden;
}
</style>